%{

/*************************************************************************
 *                                                                       *
 * This file is part of the DogosFrame distribution.  For full copyright *
 * information, see COPYRIGHT and COPYING.LESSER.                        *
 *                                                                       *
 * Author:           sqbang                                              *
 * Email:            sqbang@ustc.edu                                     *
 * Date:             2013.12.11                                          *
 * Acknowledegments: This file is a copy from SAMRAI projection          *
 *                   with slight modification.                           *
 * Description:      Lex scanner description for the input               *
 *                   database                                            *
 *                                                                       *
 *************************************************************************/

#include "COMMON/pars/Parser.h"

#include <stdlib.h>
#include <string>

using namespace std;

#define YY_NEVER_INTERACTIVE 1
#define YY_NO_UNPUT 1

using namespace DOGOS;

struct KeyData;
#include "Grammar.h"

#define YY_INPUT(b,r,s) r = Parser::get_instance()->yyinput(b, s)

#define TOKEN(T) {						\
   Parser::get_instance()->advance_cursor(yytext);	\
   return(T);							\
}

#define MAXIMUM_INCLUDE_DEPTH 16
static YY_BUFFER_STATE s_include_stack[MAXIMUM_INCLUDE_DEPTH];
static int s_include_stack_top = 0;

%}

%option noyywrap
%x COMMENT

S_CHAR    (\'[^\']\')
S_INTEGER ([-]?[0-9]+)
S_KEYWORD ([a-zA-Z\_][a-zA-Z0-9_.]*)
S_DOUBLE  (([-]?[0-9]+"."[0-9]*([Ee][+-]?[0-9]+)?)|([-]?"."[0-9]*([Ee][+-]?[0-9]+)?)|([-]?[0-9]+([Ee][+-]?[0-9]+)))
S_STRING  (\"([^\n"])*\")

%%

"&&"    TOKEN(T_AND)
"="     TOKEN(T_ASSIGN)
"}"     TOKEN(T_CLOSE_CURLY)
")"     TOKEN(T_CLOSE_PAREN)
"]"     TOKEN(T_CLOSE_SQBKT)
","     TOKEN(T_COMMA)
"/"     TOKEN(T_DIV)
":"     TOKEN(T_ELSE)
"=="    TOKEN(T_EQUALS)
"^"     TOKEN(T_EXP)
"FALSE" TOKEN(T_FALSE)
">="    TOKEN(T_GREATER_EQUALS)
">"     TOKEN(T_GREATER)
"<="    TOKEN(T_LESS_EQUALS)
"<"     TOKEN(T_LESS)
"-"     TOKEN(T_MINUS)
"*"     TOKEN(T_MULT)
"!"     TOKEN(T_NOT)
"!="    TOKEN(T_NOT_EQUALS)
"||"    TOKEN(T_OR)
"{"     TOKEN(T_OPEN_CURLY)
"("     TOKEN(T_OPEN_PAREN)
"["     TOKEN(T_OPEN_SQBKT)
"+"     TOKEN(T_PLUS)
"?"     TOKEN(T_QUESTION)
";"     TOKEN(T_SEMI)
"TRUE"  TOKEN(T_TRUE)

{S_CHAR} {
   Parser::get_instance()->advance_cursor(yytext);
   yylval.u_char = yytext[1];
   return(T_CHAR);
}

{S_INTEGER} {
   Parser::get_instance()->advance_cursor(yytext);
   yylval.u_integer = atoi(yytext);
   return(T_INTEGER);
}

{S_KEYWORD} {
   Parser::get_instance()->advance_cursor(yytext);
   yylval.u_keyword = new string(yytext);
   return(T_KEYWORD);
}

{S_DOUBLE} {
   Parser::get_instance()->advance_cursor(yytext);
   yylval.u_double = atof(yytext);
   return(T_DOUBLE);
}

{S_STRING} {
   Parser::get_instance()->advance_cursor(yytext);
   string s(yytext);
   yylval.u_string = new string(s.substr(1,s.length()-2));
   return(T_STRING);
}

[ \t]+ {
   Parser::get_instance()->advance_cursor(yytext);
}

\n.* {
   Parser::get_instance()->set_line(yytext+1);
   Parser::get_instance()->advance_line();
   yyless(1);
}

\r\n.* {
   Parser::get_instance()->set_line(yytext+1);
   Parser::get_instance()->advance_line();
   yyless(1);
}

"#include"[ \t]+\"[^\"\n]+\"[ \t]*\n {
   string s(yytext);
   string::size_type start = s.find("\"")+1;
   string::size_type end   = s.rfind("\"")-1;

   string file_name(s, start, end-start+1);

   if (s_include_stack_top >= MAXIMUM_INCLUDE_DEPTH) {
      Parser::get_instance()->error("Too many nested #include statements");
      Parser::get_instance()->advance_line();
   } else {
      if (Parser::get_instance()->push_include_file(file_name)) {
         s_include_stack[s_include_stack_top++] = YY_CURRENT_BUFFER;
         yy_switch_to_buffer(yy_create_buffer(0,YY_BUF_SIZE));
      }
   }
}

"//".*\n {
   Parser::get_instance()->advance_line();
}

"/*" {
   Parser::get_instance()->advance_cursor(yytext);
   BEGIN COMMENT;
}

<COMMENT>"/*" {
   Parser::get_instance()->advance_cursor(yytext);
   Parser::get_instance()->warning("``/*'' found within comment");
}

<COMMENT>\n {
   Parser::get_instance()->advance_line();
}

<COMMENT>"*/" {
   Parser::get_instance()->advance_cursor(yytext);
   BEGIN INITIAL;
}

<COMMENT><<EOF>> {
   Parser::get_instance()->warning("EOF detected within comment");
   yy_delete_buffer(YY_CURRENT_BUFFER);
   yyterminate();
}

<COMMENT>. {
   Parser::get_instance()->advance_cursor(yytext);
}

. {
   Parser::get_instance()->advance_cursor(yytext);
   Parser::get_instance()->warning("Illegal character token in input");
   return(yytext[0]);
}

<<EOF>> {
   yy_delete_buffer(YY_CURRENT_BUFFER);
   if (s_include_stack_top == 0) {
      yyterminate();
   } else {
      yy_switch_to_buffer(s_include_stack[--s_include_stack_top]);
      Parser::get_instance()->pop_include_file();
      Parser::get_instance()->advance_line();
   }
}

%%
